`timescale 1ns/1ps
`default_nettype none

module cxy_pixel_display_buf
    #(
    parameter   DW      = 96
    )
    (
    // write
    input  wire         I_wclk,
    input  wire [7:0]   I_wren,
    input  wire [8:0]   I_waddr,
    input  wire [23:0]  I_wdata,
    // read
    input  wire         I_rclk,
    input  wire         I_rden,
    input  wire [9:0]   I_raddr,
    output wire [DW-1:0]  O_rdata
    );
//***********************************************************
localparam  M = DW/12;

wire            rd_clk;
wire            rd_en;
wire [11:0]     rd_addr;
wire [23:0]     q;

reg  [9:0]      raddr;
reg  [3:0]      rden_sr;
reg  [1:0]      rd_turn;
reg  [DW-1:0]   q_tmp;
//***********************************************************
//-------------------------------------
// instance of dpram_512x24_4096x3
//-------------------------------------
genvar i;
generate
    for(i=0;i<M;i=i+1)
    begin: gen_ram
        dpram_512x24_4096x3 data_buf(
            .wrclock    (I_wclk     ),
            .wren       (I_wren[i]  ),
            .wraddress  (I_waddr    ),
            .data       (I_wdata    ),

            .rdclock    (rd_clk     ),
            .rden       (rd_en      ),
            .rdaddress  (rd_addr    ),
            .q          (q[i*3+2:i*3])
            );
            
        // sdpram_lpm #(
        // .A_ADDRESS_WIDTH    (   9       ),
        // .A_DATA_WIDTH       (   24      ),
        // .B_ADDRESS_WIDTH    (   12      ),
        // .B_DATA_WIDTH       (   3       )
        // )
        // data_buf(
        // .clka       (   I_wclk          ),
        // .wea        (   I_wren[i]       ),
        // .addra      (   I_waddr         ),
        // .dina       (   I_wdata         ),

        // .clkb       (   rd_clk          ),
        // .reb        (   rd_en           ),
        // .addrb      (   rd_addr         ),
        // .doutb      (   q[i*3+2:i*3]    )

        // );
    end
endgenerate
//***********************************************************
//rden_sr[3:0]
always@(posedge I_rclk)
    rden_sr <= {rden_sr[2:0],I_rden};

//rd_turn[1:0]
always@(posedge I_rclk)
    case({I_rden,rden_sr[0],rden_sr[1]})
        3'b100:     rd_turn <= 2'd1;
        3'b010:     rd_turn <= 2'd2;
        3'b001:     rd_turn <= 2'd3;
        default:    rd_turn <= 2'd0;
    endcase

//raddr[9:0]
always@(posedge I_rclk)
    if(I_rden==1)
        raddr <= I_raddr;

//rd_clk
//rd_en
//rd_addr[11:0]
assign rd_clk  = I_rclk;
assign rd_en   = I_rden | rden_sr[0] | rden_sr[1] | rden_sr[2];
assign rd_addr = I_rden ?
                 {I_raddr[9],rd_turn[1:0],I_raddr[8:0]} :
                 {  raddr[9],rd_turn[1:0],  raddr[8:0]};

//q_tmp[DW-1:0]
generate
    for(i=0;i<M;i=i+1)
    begin: gen_d_tmp
        always@(posedge I_rclk)
        case(rd_turn[1:0])
            2'd1:   q_tmp[i*12+2+0 : i*12+0] <= q[i*3+2 : i*3];
            2'd2:   q_tmp[i*12+2+3 : i*12+3] <= q[i*3+2 : i*3];
            2'd3:   q_tmp[i*12+2+6 : i*12+6] <= q[i*3+2 : i*3];
            2'd0:   q_tmp[i*12+2+9 : i*12+9] <= q[i*3+2 : i*3]; // 可以删掉
        endcase
    end
endgenerate

//O_rdata[DW-1:0]
generate
    for(i=0;i<M;i=i+1)
    begin: gen_rdata_h
        assign O_rdata[i*12+8  : i*12+0] = q_tmp[i*12+8 : i*12];
        assign O_rdata[i*12+11 : i*12+9] = q[i*3+2 : i*3];
    end
endgenerate
//***********************************************************
endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
